home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 October / Macworld (1998-10).dmg / Shareware World / Info / For Developers / MacZoop 1.8.4 / More Classes / Streaming Classes / ZStream.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-07  |  15.4 KB  |  627 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZStream.h            -- a generic stream (abstract class- use ZHandleStream or
  9. *                                                                        ZFileStream ).
  10. *
  11. *
  12. *
  13. *
  14. *
  15. *            © 1998, Graham Cox
  16. *
  17. *
  18. *
  19. *
  20. *************************************************************************************************/
  21.  
  22. #include    "ZStream.h"
  23. #include    "ZArray.h"
  24. #include    "ZObject.h"
  25. #include    "ZDefines.h"
  26. #include    "ZErrors.h"
  27. #include    "ZClassRegistry.h"
  28.  
  29.  
  30. /*--------------------------------***  CONSTRUCTOR  ***-----------------------------------*/
  31.  
  32.  
  33. ZStream::ZStream()
  34. {
  35.     mark = 0;
  36.     idSeed = 1;
  37.     
  38.     refTable = NULL;
  39. }
  40.  
  41.  
  42. /*---------------------------------***  DESTRUCTOR  ***----------------------------------*/
  43.  
  44.  
  45. ZStream::~ZStream()
  46. {
  47.     if ( refTable )
  48.         ForgetObject( refTable );
  49. }
  50.  
  51.  
  52.  
  53. /*----------------------------------***  READCHAR  ***-----------------------------------*/
  54. /*    
  55. read the next character from the stream
  56. -----------------------------------------------------------------------------------------*/
  57.  
  58. void        ZStream::ReadChar( char* aChar )
  59. {
  60.     long    dlen = sizeof( char );
  61.     
  62.     GetFrom( aChar, &dlen );
  63. }
  64.  
  65.  
  66. /*---------------------------------***  READSHORT  ***-----------------------------------*/
  67. /*    
  68. read the next short word from the stream
  69. -----------------------------------------------------------------------------------------*/
  70.  
  71. void        ZStream::ReadShort( short* aShort )
  72. {
  73.     long    dlen = sizeof( short );
  74.     
  75.     GetFrom( aShort, &dlen );
  76. }
  77.  
  78.  
  79. /*----------------------------------***  READLONG  ***-----------------------------------*/
  80. /*    
  81. read the next long word from the stream
  82. -----------------------------------------------------------------------------------------*/
  83.  
  84. void        ZStream::ReadLong( long* aLong )
  85. {
  86.     long    dlen = sizeof( long );
  87.     
  88.     GetFrom( aLong, &dlen );
  89. }
  90.  
  91.  
  92. /*---------------------------------***  READFLOAT  ***-----------------------------------*/
  93. /*    
  94. read the next floating point value from the stream
  95. -----------------------------------------------------------------------------------------*/
  96.  
  97. void        ZStream::ReadFloat( float* aFloat )
  98. {
  99.     long    dlen = sizeof( float );
  100.     
  101.     GetFrom( aFloat, &dlen );
  102. }
  103.  
  104.  
  105. /*---------------------------------***  READSTRING  ***----------------------------------*/
  106. /*    
  107. read the next pascal string from the stream
  108. -----------------------------------------------------------------------------------------*/
  109.  
  110. void        ZStream::ReadString( Str255 aString )
  111. {
  112.     char    slen;
  113.     long    dlen;
  114.     
  115.     ReadChar( &slen );
  116.     dlen = (long) slen + 1;
  117.     Skip( -1 );
  118.     GetFrom((Ptr) aString, &dlen );
  119. }
  120.  
  121.  
  122. /*----------------------------------***  READDATA  ***-----------------------------------*/
  123. /*    
  124. read arbitrary block of data from the stream. Data is stored as length (long word) followed
  125. by the data bytes.
  126. -----------------------------------------------------------------------------------------*/
  127.  
  128. void        ZStream::ReadData( Ptr aBuf, long* dataLen )
  129. {
  130.     // if you pass NULL in <aBuf>, you can read the size and skip the rest of the
  131.     // data if you want to allocate space first- you should then skip back by
  132.     // dataLen + 4 to re-read the data. Alternatively read the size using ReadLong first,
  133.     // then skip back 4 to call this.
  134.     
  135.     ReadLong( dataLen );
  136.     
  137.     if ( aBuf )
  138.         GetFrom( aBuf, dataLen );
  139.     else
  140.         Skip( *dataLen );
  141. }
  142.  
  143.  
  144. /*---------------------------------***  READHANDLE  ***----------------------------------*/
  145. /*    
  146. read data from stream into handle- handle is resized to suit. Handle data is stored as
  147. length (long word) followed by handle content bytes
  148. -----------------------------------------------------------------------------------------*/
  149.  
  150. void        ZStream::ReadHandle( Handle* aHand )
  151. {
  152.     Handle    h;
  153.     long    hs;
  154.     
  155.     FailNILParam( aHand );
  156.     ReadLong( &hs );
  157.     
  158.     if ( hs == 'null' )
  159.         h = NULL;
  160.     else
  161.     {
  162.         FailNIL( h = NewHandle( hs ));
  163.         
  164.         HLock( h );
  165.         GetFrom( *h, &hs );
  166.         HUnlock( h );
  167.     }
  168.     
  169.     *aHand = h;
  170. }
  171.  
  172.  
  173. /*-----------------------------***  READOBJECTREFERENCE  ***-----------------------------*/
  174. /*    
  175. return an object from the stream. This correctly returns objects referred multiply within
  176. a single stream.
  177. -----------------------------------------------------------------------------------------*/
  178.  
  179. ZObject*    ZStream::ReadObject()
  180. {
  181.     long                classID, instanceID, index;
  182.     ObjRef_T_Entry        oti;
  183.     ZObject*            theObj = NULL;
  184.     
  185. #if _MACZOOP_STREAMS
  186.     
  187.     if ( refTable == NULL )
  188.         FailNIL( refTable = new ZArray( sizeof( ObjRef_T_Entry )));
  189.     
  190.     ReadLong( &classID );
  191.     ReadLong( &instanceID );
  192.     
  193.     // check for the special 'null' marker- if it's there, we just return NULL since there's
  194.     // nothing else to do.
  195.     
  196.     if ( classID != 'null' )
  197.     {
  198.         index = FindObjectReference( classID, instanceID );
  199.         
  200.         if ( index > 0 )
  201.         {
  202.             // we encountered this one earlier, so return the ref we made then
  203.             
  204.             refTable->GetArrayItem( &oti, index );
  205.         
  206.             theObj = oti.theObject;
  207.         }
  208.         else
  209.         {
  210.             // this is a new one, so make it by calling the class registry to construct
  211.             // it, then pass the stream to the object to initialise its data. We also
  212.             // make an entry in the ref table for it in case something refers to it
  213.             // further along the stream. The class registry assumes the next data in
  214.             // the stream is the class ID, so wind the stream back 8 bytes first...
  215.             
  216.             Skip( -2 * sizeof( long ));
  217.             
  218.             // build the object. In order to work, the object class must have been registered with
  219.             // <gClasses> at some point previously. This is normally done at app startup time.
  220.             
  221.             theObj = gClasses->InstantiateFromStream( this );
  222.             
  223.             // store a ref to it for later. For this to work, it is IMPERATIVE that stream users
  224.             // do not delete any objects obtained from the stream until the stream itself is no
  225.             // longer needed, otherwise this technique will fail big time.
  226.         
  227.             oti.theObject = theObj;
  228.             oti.classID = classID;
  229.             oti.instanceID = instanceID;
  230.         
  231.             refTable->AppendItem( &oti );
  232.         }
  233.     }
  234. #else
  235.     FailOSErr( kStreamsNotPresentErr );
  236.     
  237. #endif
  238.  
  239.     return theObj;
  240. }
  241.  
  242.  
  243. /*----------------------------------***  READRECT  ***-----------------------------------*/
  244. /*    
  245. read a quickdraw rect from the stream
  246. -----------------------------------------------------------------------------------------*/
  247.  
  248. void        ZStream::ReadRect( Rect* aRect )
  249. {
  250.     long dLen = sizeof( Rect );
  251.     GetFrom( aRect, &dLen );
  252. }
  253.  
  254.  
  255. /*---------------------------------***  READPOINT  ***-----------------------------------*/
  256. /*    
  257. read a quickdraw point from the stream
  258. -----------------------------------------------------------------------------------------*/
  259.  
  260. void        ZStream::ReadPoint( Point* aPoint )
  261. {
  262.     long dLen = sizeof( Point );
  263.     GetFrom( aPoint, &dLen );
  264. }
  265.  
  266.  
  267. /*-------------------------------***  READGRAFPORT  ***----------------------------------*/
  268. /*    
  269. read the state of a grafport from the stream
  270. -----------------------------------------------------------------------------------------*/
  271.  
  272. void        ZStream::ReadGrafPort( GrafPtr aPort )
  273. {
  274.     GrafPtr        savePort;
  275.     RgnHandle    clip;
  276.     PenState    ps;
  277.     char        ffc;
  278.     short        ffs;
  279.     long        ffl;
  280.     RGBColor    cc;
  281.     Str255        fontName;
  282.     
  283.     FailNILParam( aPort );
  284.     
  285.     GetPort( &savePort );
  286.     SetPort( aPort );
  287.     
  288.     ReadRect( &aPort->portRect );
  289.     ReadHandle((Handle*) &clip );
  290.     
  291.     if ( clip )
  292.     {
  293.         SetClip( clip );
  294.         DisposeRgn( clip );
  295.     }
  296.     
  297.     ffl = sizeof( PenState );
  298.     ReadData((Ptr) &ps, &ffl );
  299.     SetPenState( &ps );
  300.     
  301.     ReadHandle((Handle*) &clip );
  302.     
  303.     if ( clip )
  304.     {
  305.         CopyRgn( clip, aPort->visRgn );
  306.         DisposeRgn( clip );
  307.     }
  308.     
  309.     ReadShort( &ffs );
  310.     TextSize( ffs );
  311.     ReadShort( &ffs );
  312.     TextMode( ffs );
  313.     ReadChar( &ffc );
  314.     TextFace((Style) ffc );
  315.     ReadLong( &ffl );
  316.     SpaceExtra((Fixed) ffl );
  317.     
  318.     ReadString( fontName );
  319.     GetFNum( fontName, &ffs );
  320.     TextFont( ffs );
  321.     
  322.     ReadColour( &cc );
  323.     RGBForeColor( &cc );
  324.     ReadColour( &cc );
  325.     RGBBackColor( &cc );
  326.     
  327.     SetPort( savePort );
  328. }
  329.  
  330.  
  331. /*--------------------------------***  READCOLOUR  ***-----------------------------------*/
  332. /*    
  333. read a rgb colour from the stream
  334. -----------------------------------------------------------------------------------------*/
  335.  
  336. void        ZStream::ReadColour( RGBColor* rgb )
  337. {
  338.     long dlen = sizeof( RGBColor );
  339.     GetFrom( rgb, &dlen );
  340. }
  341.  
  342.  
  343. /*---------------------------------***  WRITECHAR  ***-----------------------------------*/
  344. /*    
  345. write a single character to the stream
  346. -----------------------------------------------------------------------------------------*/
  347.  
  348. void        ZStream::WriteChar( char aChar )
  349. {
  350.     PutTo( &aChar, sizeof( char ));
  351. }
  352.  
  353.  
  354. /*--------------------------------***  WRITESHORT  ***-----------------------------------*/
  355. /*    
  356. write a single short word to the stream
  357. -----------------------------------------------------------------------------------------*/
  358.  
  359. void        ZStream::WriteShort( short aShort )
  360. {
  361.     PutTo( &aShort, sizeof( short ));
  362. }
  363.  
  364.  
  365. /*---------------------------------***  WRITELONG  ***-----------------------------------*/
  366. /*    
  367. write a single long word to the stream
  368. -----------------------------------------------------------------------------------------*/
  369.  
  370. void        ZStream::WriteLong( long aLong )
  371. {
  372.     PutTo( &aLong, sizeof( long ));
  373. }
  374.  
  375.  
  376. /*--------------------------------***  WRITEFLOAT  ***----------------------------------*/
  377. /*    
  378. write a single floating point value to the stream
  379. -----------------------------------------------------------------------------------------*/
  380.  
  381. void        ZStream::WriteFloat( float aFloat )
  382. {
  383.     PutTo( &aFloat, sizeof( float ));
  384. }
  385.  
  386.  
  387. /*--------------------------------***  WRITESTRING  ***----------------------------------*/
  388. /*    
  389. write a single pascal string to the stream
  390. -----------------------------------------------------------------------------------------*/
  391.  
  392. void        ZStream::WriteString( Str255 aString )
  393. {
  394.     PutTo( aString, aString[0] + 1 );
  395. }
  396.  
  397.  
  398. /*---------------------------------***  WRITEDATA  ***-----------------------------------*/
  399. /*    
  400. write an arbitrary block of data to the stream
  401. -----------------------------------------------------------------------------------------*/
  402.  
  403. void        ZStream::WriteData( Ptr aBuf, long dataLen )
  404. {
  405.     // arbitrary data is written as a length count, followed by the data.
  406.     
  407.     FailNILParam( aBuf );
  408.     WriteLong( dataLen );
  409.     PutTo( aBuf, dataLen );
  410. }
  411.  
  412.  
  413. /*--------------------------------***  WRITEHANDLE  ***----------------------------------*/
  414. /*    
  415. write contents of any handle to the stream. It's OK for the handle to be NULL.
  416. -----------------------------------------------------------------------------------------*/
  417.  
  418. void        ZStream::WriteHandle( Handle aHand )
  419. {
  420.     if ( aHand )
  421.     {
  422.         long    hs = GetHandleSize( aHand );
  423.         char    hState = HGetState( aHand );
  424.         
  425.         // handles are written with their size followed by the data
  426.         
  427.         WriteLong( hs );
  428.         
  429.         HLock( aHand );
  430.         
  431.         PutTo( *aHand, hs );
  432.         HSetState( aHand, hState );
  433.     }
  434.     else
  435.         WriteLong( 'null' );
  436. }
  437.  
  438.  
  439. /*----------------------------***  WRITEOBJECTREFERENCE  ***-----------------------------*/
  440. /*    
  441. write an object reference to the stream. This returns <TRUE> if you are expected to write
  442. further data to the stream for the object, or <FALSE> if this was already done for this
  443. object earlier.
  444. -----------------------------------------------------------------------------------------*/
  445.  
  446. void        ZStream::WriteObject( ZObject* anObject )
  447. {
  448.     // to write an object reference, we assign it an instance ID and gets its class ID-
  449.     // these are then written to the file. If the same object is written again later, we
  450.     // write the same IDs as before.
  451.     
  452. #if _MACZOOP_STREAMS
  453.     Boolean     wasWritten = FALSE;
  454.     
  455.     if ( refTable == NULL )
  456.         FailNIL( refTable = new ZArray( sizeof( ObjRef_T_Entry )));
  457.     
  458.     ObjRef_T_Entry    oti;    
  459.     long             index = FindObjectReference( anObject );
  460.     
  461.     if ( anObject && ( index > 0 ))
  462.     {
  463.         // we've seen this one before, so get its IDs and write them to the stream
  464.         
  465.         refTable->GetArrayItem( &oti, index );
  466.     }
  467.     else
  468.     {
  469.         // nope, this is a new one on me, so create an entry for it in the table and
  470.         // write the data to the stream. The instance ID itself is not significant- all
  471.         // that matters is that it is unique for the given class/instance. We just allocate
  472.         // a sequential number from our seed.
  473.         
  474.         // if the object is NULL, we write a special marker to the stream to tell us to return
  475.         // NULL when the stream is read back in.
  476.         
  477.         if ( anObject == NULL )
  478.         {
  479.             oti.classID = 'null';
  480.             oti.instanceID = '0000';
  481.         }
  482.         else
  483.         {
  484.             oti.theObject = anObject;
  485.             oti.instanceID = idSeed++;
  486.             oti.classID = anObject->GetClassRef();
  487.         
  488.             refTable->AppendItem( &oti );
  489.             
  490.             wasWritten = TRUE;
  491.         }
  492.         // for the first instance of an object encountered, the caller is expected to write the
  493.         // object's state data immediately following. If this function returns TRUE, you should
  494.         // write this data, otherwise do not bother.
  495.     }
  496.     
  497.     PutTo( &oti.classID, sizeof( long ));
  498.     PutTo( &oti.instanceID, sizeof( long ));
  499.     
  500.     if ( wasWritten )
  501.         anObject->WriteToStream( this );
  502. #else
  503.     FailOSErr( kStreamsNotPresentErr );
  504.     
  505. #endif
  506. }
  507.  
  508.  
  509. /*---------------------------------***  WRITERECT  ***-----------------------------------*/
  510. /*    
  511. write quickdraw rectangle to the stream
  512. -----------------------------------------------------------------------------------------*/
  513.  
  514. void        ZStream::WriteRect( Rect* aRect )
  515. {
  516.     PutTo( aRect, sizeof( Rect ));
  517. }
  518.  
  519.  
  520. /*---------------------------------***  WRITEPOINT  ***----------------------------------*/
  521. /*    
  522. write quickdraw point to the stream
  523. -----------------------------------------------------------------------------------------*/
  524.  
  525. void        ZStream::WritePoint( Point aPoint )
  526. {
  527.     PutTo( &aPoint, sizeof( Point ));
  528. }
  529.  
  530.  
  531. /*-------------------------------***  WRITEGRAFPORT  ***---------------------------------*/
  532. /*    
  533. write quickdraw grafport state to stream (pen, font, etc)
  534. -----------------------------------------------------------------------------------------*/
  535.  
  536. void        ZStream::WriteGrafPort( GrafPtr aPort )
  537. {
  538.     FailNILParam( aPort );
  539.     
  540.     GrafPtr        savePort;
  541.     PenState    ps;
  542.     RgnHandle    clip;
  543.     RGBColor    cc;
  544.     Str255        fontName;
  545.     
  546.     GetPort( &savePort );
  547.     SetPort( aPort );
  548.     GetPenState( &ps );
  549.     GetClip( clip = NewRgn());
  550.     
  551.     WriteRect( &aPort->portRect );
  552.     WriteHandle((Handle) clip );
  553.     WriteData((Ptr) &ps, sizeof( PenState ));
  554.     
  555.     CopyRgn( aPort->visRgn, clip );
  556.     WriteHandle((Handle) clip );
  557.     
  558.     WriteShort( aPort->txSize );
  559.     WriteShort( aPort->txMode );
  560.     WriteChar((char) aPort->txFace );
  561.     WriteLong((long) aPort->spExtra );    
  562.     
  563.     GetFontName( aPort->txFont, fontName );
  564.     WriteString( fontName );
  565.     
  566.     GetForeColor( &cc );
  567.     WriteColour( &cc );
  568.     GetBackColor( &cc );
  569.     WriteColour( &cc );    
  570.     
  571.     DisposeRgn( clip );
  572.     SetPort( savePort );
  573. }
  574.  
  575.  
  576. /*--------------------------------***  WRITECOLOUR  ***----------------------------------*/
  577. /*    
  578. write rgb colour to the stream
  579. -----------------------------------------------------------------------------------------*/
  580.  
  581. void        ZStream::WriteColour( RGBColor* rgb )
  582. {
  583.     PutTo( rgb, sizeof( RGBColor ));
  584. }
  585.  
  586.  
  587. /*----------------------------***  FINDOBJECTREFERENCE  ***------------------------------*/
  588. /*    
  589. return index of object in local temporary reference table (internal method)
  590. -----------------------------------------------------------------------------------------*/
  591.  
  592. long        ZStream::FindObjectReference( ZObject* anObject )
  593. {
  594.     long            i;
  595.     ObjRef_T_Entry    oti;
  596.     
  597.     for( i = 1; i <= refTable->CountItems(); i++ )
  598.     {
  599.         refTable->GetArrayItem( &oti, i );
  600.         
  601.         if ( oti.theObject == anObject )
  602.             return i;
  603.     }
  604.     
  605.     return 0;
  606. }
  607.  
  608.  
  609. /*----------------------------***  FINDOBJECTREFERENCE  ***------------------------------*/
  610.  
  611. long        ZStream::FindObjectReference( long classID, long instanceID )
  612. {
  613.     long            i;
  614.     ObjRef_T_Entry    oti;
  615.     
  616.     for( i = 1; i <= refTable->CountItems(); i++ )
  617.     {
  618.         refTable->GetArrayItem( &oti, i );
  619.         
  620.         if (( oti.classID == classID ) &&
  621.             ( oti.instanceID == instanceID ))
  622.             return i;
  623.     }
  624.     
  625.     return 0;
  626. }
  627.